Nucleotide diversity
Nucleotide diversity (often referred to using the symbol π) is the
average pairwise difference between all possible pairs of individuals in
your sample. It is a very intuitive and simple measure of genetic
diversity, and is accurately estimated even with very few samples. A
formal definition is here.
We can obtain the nucleotide diversity (Ï€) from our VCF file using
vcftools software. In our case we will collect the π value from each 10
kb (10,000 bp) window of the genome.
NB: vcftools is a very flexible tool for analyzing, manipulating VCF
files. It can do many other wonderful things. The vcftools manual is on
github here (https://vcftools.sourceforge.net/man_latest.html).
Breaking up pi by treatment type?
I believe that an important step would be to compare nucleotide
diversity between the different treatment groups. The following code
present information for all treatment groups and compares it to each
individual treatment group.
Start of modified workflow
Setup
The following was run on the command line
# Make ROD_CADO_working directory in home
mkdir ROD_CADO_working
cd ROD_CADO_working
# Make Nucleotide_diversity directory
mkdir ROD_CADO_working
# create popmap file with sample and treatment names
cp /home/Shared_Data/ROD_CADO/analysis/popmap popmap
# manually add in treatment names to popmap file (w/ code)
head treat_popmap
C1_2 con-con C1_4 con-con C1_5 con-con C1_6 con-con C1_7 con-con C1_8
con-con C1_9 con-con C2_10 con-con C2_11 con-con C2_2 con-con
Subsetting popmap groups
Create treatment specific files containing a single column of all of
the sample names within that treatment
awk '$2 == "con-con" {print $1}' treat_popmap > con-con.txt | awk '$2 == "str-con" {print $1}' treat_popmap > str-con.txt | awk '$2 == "con-rod" {print $1}' treat_popmap > con-rod.txt | awk '$2 == "str-rod" {print $1}' treat_popmap > str-rod.txt
Make script with loop using ChatGPT
Make script
#!/bin/bash
VCF=SNP.TRSdp10g1.FIL.vcf.gz
POPS=("con-con" "str-con" "con-rod" "str-rod")
for POP in "${POPS[@]}"; do
echo "Processing $POP..."
KEEP="popmap_files/${POP}.txt"
OUT_PREFIX="temp_${POP//-}"
REC_VCF="${OUT_PREFIX}.recode.vcf"
REC_VCFGZ="${REC_VCF}.gz"
OUTPUT_PI="ROD.CADO.${POP}.pi.windowed.pi"
# Step 1: Filter and recode
vcftools --gzvcf "$VCF" \
--keep "$KEEP" \
--recode --recode-INFO-all \
--out "$OUT_PREFIX"
# Step 2: Compress VCF and remove uncompressed
bgzip "$REC_VCF"
rm "$REC_VCF"
# Step 3: Calculate windowed pi
vcftools --gzvcf "$REC_VCFGZ" \
--window-pi 10000 \
--out "$OUTPUT_PI"
# Step 4: Clean up compressed VCF
rm "$REC_VCFGZ"
echo "Finished processing $POP"
echo "---------------------------"
done
Make executable
chmod +x run_pi_calculations.sh
Run in tmux
# Run in tmux
tmux new -s pi_calc
# Reattach later
tmux attach-session -t pi_calc
Load dataframe
pi.all.dataframe<-read.table("/home/Shared_Data/ROD_CADO/analysis/raw.vcf/ROD.CADO.all.pi.windowed.pi", sep="\t", header=T)
pi.concon.dataframe<-read.table("/home/jgreen/ROD_CADO_working/Nucleotide_diversity/ROD.CADO.con-con.pi.windowed.pi.windowed.pi", sep="\t", header=T)
pi.conrod.dataframe<-read.table("/home/jgreen/ROD_CADO_working/Nucleotide_diversity/ROD.CADO.con-rod.pi.windowed.pi.windowed.pi", sep="\t", header=T)
pi.strcon.dataframe<-read.table("/home/jgreen/ROD_CADO_working/Nucleotide_diversity/ROD.CADO.str-con.pi.windowed.pi.windowed.pi", sep="\t", header=T)
pi.strrod.dataframe<-read.table("/home/jgreen/ROD_CADO_working/Nucleotide_diversity/ROD.CADO.str-rod.pi.windowed.pi.windowed.pi", sep="\t", header=T)
Color palette
#Here is the color pallette that we will use for everything:
col_pal <- c("#0072B2", "#56B4E9", "#E69F00", "#F0E442")
#Let's factor treatments as follows:
df$TREAT <- factor(df$TREAT, levels=c("CONCON", "STRCON", "CONROD", "STRROD"))
Modify CHROM column in dataframe
pi.all.dataframe %>%
mutate(CHROM = str_replace(CHROM, "NC_035780.1", "1")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035781.1", "2")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035782.1", "3")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035783.1", "4")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035784.1", "5")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035785.1", "6")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035786.1", "7")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035787.1", "8")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035788.1", "9")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035789.1", "10")) -> pi.all.df
pi.all.df$CHROM <- as.factor(pi.all.df$CHROM)
pi.concon.dataframe %>%
mutate(CHROM = str_replace(CHROM, "NC_035780.1", "1")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035781.1", "2")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035782.1", "3")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035783.1", "4")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035784.1", "5")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035785.1", "6")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035786.1", "7")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035787.1", "8")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035788.1", "9")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035789.1", "10")) -> pi.concon.df
pi.concon.df$CHROM <- as.factor(pi.concon.df$CHROM)
pi.conrod.dataframe %>%
mutate(CHROM = str_replace(CHROM, "NC_035780.1", "1")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035781.1", "2")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035782.1", "3")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035783.1", "4")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035784.1", "5")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035785.1", "6")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035786.1", "7")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035787.1", "8")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035788.1", "9")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035789.1", "10")) -> pi.conrod.df
pi.conrod.df$CHROM <- as.factor(pi.conrod.df$CHROM)
pi.strcon.dataframe %>%
mutate(CHROM = str_replace(CHROM, "NC_035780.1", "1")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035781.1", "2")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035782.1", "3")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035783.1", "4")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035784.1", "5")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035785.1", "6")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035786.1", "7")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035787.1", "8")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035788.1", "9")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035789.1", "10")) -> pi.strcon.df
pi.strcon.df$CHROM <- as.factor(pi.strcon.df$CHROM)
pi.strrod.dataframe %>%
mutate(CHROM = str_replace(CHROM, "NC_035780.1", "1")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035781.1", "2")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035782.1", "3")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035783.1", "4")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035784.1", "5")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035785.1", "6")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035786.1", "7")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035787.1", "8")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035788.1", "9")) %>%
mutate(CHROM = str_replace(CHROM, "NC_035789.1", "10")) -> pi.strrod.df
pi.strrod.df$CHROM <- as.factor(pi.strrod.df$CHROM)
For loop to replace previous dataframe manipulation
# Create named vector to map chromosome names
chrom_map <- setNames(as.character(1:10), paste0("NC_03578", 0:9, ".1"))
# List of original dataframe names (as strings)
input_names <- c(
"pi.all.dataframe",
"pi.concon.dataframe",
"pi.conrod.dataframe",
"pi.strcon.dataframe",
"pi.strrod.dataframe"
)
# Corresponding output dataframe names
output_names <- c(
"pi.all.df",
"pi.concon.df",
"pi.conrod.df",
"pi.strcon.df",
"pi.strrod.df"
)
# Loop through each dataframe
for (i in seq_along(input_names)) {
df <- get(input_names[i]) # retrieve the dataframe by name
# Replace chromosome names
for (old in names(chrom_map)) {
df <- df %>% mutate(CHROM = str_replace(CHROM, old, chrom_map[[old]]))
}
# Convert to factor
df$CHROM <- as.factor(df$CHROM)
# Assign to new name in global environment
assign(output_names[i], df)
}
Descriptive statistics
summary(pi.all.df)
by(pi.all.df, pi.all.df$CHROM, summary)
cor(pi.all.df$N_VARIANTS, pi.all.df$PI)
summary(pi.concon.df)
by(pi.concon.df, pi.concon.df$CHROM, summary)
cor(pi.concon.df$N_VARIANTS, pi.concon.df$PI)
summary(pi.conrod.df)
by(pi.conrod.df, pi.conrod.df$CHROM, summary)
cor(pi.conrod.df$N_VARIANTS, pi.conrod.df$PI)
summary(pi.strcon.df)
by(pi.strcon.df, pi.strcon.df$CHROM, summary)
cor(pi.strcon.df$N_VARIANTS, pi.strcon.df$PI)
summary(pi.strrod.df)
by(pi.strrod.df, pi.strrod.df$CHROM, summary)
cor(pi.strrod.df$N_VARIANTS, pi.strrod.df$PI)
New loop and plotting for statistics
col_pal <- c(
"ALL" = "gray70",
"CONCON" = "#0072B2",
"STRCON" = "#56B4E9",
"CONROD" = "#E69F00",
"STRROD" = "#F0E442"
)
df_names <- c("pi.all.df", "pi.concon.df", "pi.strcon.df", "pi.conrod.df", "pi.strrod.df")
df_labels <- c("ALL", "CONCON", "STRCON", "CONROD", "STRROD")
chrom_levels <- as.character(1:10)
summary_list <- list()
for (i in seq_along(df_names)) {
df <- get(df_names[i])
treat <- df_labels[i]
df$TREAT <- factor(treat, levels = names(col_pal))
chrom_summary <- df %>%
group_by(CHROM, TREAT) %>%
summarise(
mean_PI = mean(PI, na.rm = TRUE),
se_PI = sd(PI, na.rm = TRUE) / sqrt(n()),
mean_N_VARIANTS = mean(N_VARIANTS, na.rm = TRUE),
se_N_VARIANTS = sd(N_VARIANTS, na.rm = TRUE) / sqrt(n()),
.groups = "drop"
) %>%
mutate(CHROM = factor(CHROM, levels = chrom_levels))
summary_list[[i]] <- chrom_summary
}
summary_df <- bind_rows(summary_list)
mean_pi_plot <- ggplot(summary_df, aes(x = CHROM, y = mean_PI, fill = TREAT)) +
geom_bar(stat = "identity", position = position_dodge(width = 0.8)) +
geom_errorbar(aes(ymin = mean_PI - se_PI, ymax = mean_PI + se_PI),
position = position_dodge(width = 0.8), width = 0.2) +
scale_fill_manual(values = col_pal, name = "Treatment") +
labs(title = "Mean PI per Chromosome", x = "Chromosome", y = "Mean PI") +
theme_minimal()
mean_n_plot <- ggplot(summary_df, aes(x = CHROM, y = mean_N_VARIANTS, fill = TREAT)) +
geom_bar(stat = "identity", position = position_dodge(width = 0.8)) +
geom_errorbar(aes(ymin = mean_N_VARIANTS - se_N_VARIANTS, ymax = mean_N_VARIANTS + se_N_VARIANTS),
position = position_dodge(width = 0.8), width = 0.2) +
scale_fill_manual(values = col_pal, name = "Treatment") +
labs(title = "Mean number of variants per Chromosome", x = "Chromosome", y = "Mean # variants") +
theme_minimal()
print(mean_pi_plot)


print(mean_n_plot)
ggsave("mean_pi_plot.png", plot = mean_pi_plot, width = 10, height = 6, dpi = 300)
ggsave("mean_n_variants_plot.png", plot = mean_n_plot, width = 10, height = 6, dpi = 300)

Correlation visualizations
for (i in seq_along(df_names)) {
df <- get(df_names[i])
label <- df_labels[i]
p <- ggplot(df, aes(x = N_VARIANTS, y = PI)) +
geom_point(alpha = 0.4) +
geom_smooth(method = "lm", se = FALSE, color = "blue") +
labs(title = paste("Correlation: PI vs # variants —", label),
x = "N_VARIANTS",
y = "PI") +
theme_minimal()
print(p)
}





Table of correlations
cor_table <- tibble(
dataset = df_labels,
correlation = map_dbl(df_names, ~ cor(get(.x)$N_VARIANTS, get(.x)$PI, use = "complete.obs"))
)
print(cor_table)
Plot PI by chromosome
ggplot(pi.all.df, aes(x=CHROM, y=PI,))+
geom_violin(aes(color=CHROM,fill=CHROM))+
geom_boxplot(aes(fill=CHROM), width=0.1,outlier.shape = 23, outlier.color = "black")+
stat_summary(fun=mean, geom="point", shape=23, size=2)+
scale_fill_brewer(palette = "Paired")+
theme_classic()
Plot PI by chromosome loop
# List of dataframes and labels
df_names <- c("pi.all.df", "pi.concon.df", "pi.conrod.df", "pi.strcon.df", "pi.strrod.df")
df_labels <- c("All", "ConCon", "ConRod", "StrCon", "StrRod")
# Standard chromosome order
chrom_levels <- as.character(1:10)
# Combine all into one dataframe
combined_df <- purrr::map2_dfr(df_names, df_labels, function(df_name, label) {
df <- get(df_name)
df %>%
mutate(
dataset = label,
CHROM = factor(CHROM, levels = chrom_levels)
)
})
# Faceted violin + boxplot
ggplot(combined_df, aes(x = CHROM, y = PI)) +
geom_violin(aes(color = CHROM, fill = CHROM), trim = FALSE) +
geom_boxplot(aes(fill = CHROM), width = 0.1, outlier.shape = 23, outlier.color = "black") +
stat_summary(fun = mean, geom = "point", shape = 23, size = 2) +
scale_fill_brewer(palette = "Paired") +
labs(title = "PI Distribution by Chromosome (Faceted by Dataset)",
x = "Chromosome", y = "PI") +
facet_wrap(~ dataset, ncol = 2) +
theme_classic() +
theme(legend.position = "none")

Smaller visualizations
hist(mydf$PI,br=40)
boxplot(mydf$PI, ylab="Nuc Diversity")
Plot By position
ggplot(pi.all.df, aes(x=BIN_START, y=PI, color=CHROM))+
geom_point()+
scale_fill_brewer(palette = "Paired") +
scale_x_continuous(labels = label_number(scale = 1e-6, suffix = "M")) +
facet_wrap(~CHROM)+
theme_classic()
Loop for plot by position
# Define dataframe names and labels
df_names <- c("pi.all.df", "pi.concon.df", "pi.conrod.df", "pi.strcon.df", "pi.strrod.df")
df_labels <- c("ALL", "CONCON", "CONROD", "STRCON", "STRROD")
# Get global PI range
all_pi_values <- unlist(lapply(df_names, function(x) get(x)$PI))
global_ymin <- min(all_pi_values, na.rm = TRUE)
global_ymax <- max(all_pi_values, na.rm = TRUE)
# Loop over dataframes
for (i in seq_along(df_names)) {
df <- get(df_names[i])
label <- df_labels[i]
# Ensure CHROM is a factor ordered from 1 to 10
df$CHROM <- factor(df$CHROM, levels = as.character(1:10))
p <- ggplot(df, aes(x = BIN_START, y = PI, color = CHROM)) +
geom_point() +
facet_wrap(~CHROM) +
scale_fill_brewer(palette = "Paired") +
scale_x_continuous(labels = label_number(scale = 1e-6, suffix = "M")) + # Human readable x-axis
ylim(global_ymin, global_ymax) + # Same y-axis for all plots
theme_classic() +
labs(title = paste("PI vs BIN_START -", label),
x = "BIN_START (millions)",
y = "PI")
print(p)
ggsave(filename = paste0("PI_vs_BIN_START_", label, ".png"),
plot = p, width = 10, height = 6, dpi = 300)
}





Facet wrap chromosome showing them across different treatment
types
# Define dataframe names and labels
df_names <- c("pi.all.df", "pi.concon.df", "pi.conrod.df", "pi.strcon.df", "pi.strrod.df")
df_labels <- c("ALL", "CONCON", "CONROD", "STRCON", "STRROD")
# Custom color palette
col_pal <- c(
"ALL" = "gray70",
"CONCON" = "#0072B2",
"STRCON" = "#56B4E9",
"CONROD" = "#E69F00",
"STRROD" = "#F0E442"
)
# Combine all data into one dataframe with treatment labels
all_data <- bind_rows(lapply(seq_along(df_names), function(i) {
df <- get(df_names[i])
df$Treatment <- df_labels[i]
df
}))
# Set CHROM and Treatment as ordered factors
all_data$CHROM <- factor(all_data$CHROM, levels = as.character(1:10))
all_data$Treatment <- factor(all_data$Treatment, levels = df_labels)
# Get global PI range
global_ymin <- min(all_data$PI, na.rm = TRUE)
global_ymax <- max(all_data$PI, na.rm = TRUE)
# Loop through chromosomes 1 to 10
for (chr in 1:10) {
chr_str <- as.character(chr)
chr_data <- filter(all_data, CHROM == chr_str)
p <- ggplot(chr_data, aes(x = BIN_START, y = PI, color = Treatment)) +
geom_point(alpha = 0.6, size = 0.5) +
facet_wrap(~Treatment, nrow = 1) +
scale_color_manual(values = col_pal) +
scale_x_continuous(labels = label_number(scale = 1e-6, suffix = "M")) +
ylim(global_ymin, global_ymax) +
theme_classic() +
labs(
title = paste("Chromosome", chr, "- PI across Treatment Types"),
x = "BIN_START (millions)",
y = "PI"
)
print(p)
ggsave(
filename = paste0("PI_chr", chr, "_across_treatments.png"),
plot = p,
width = 16,
height = 4,
dpi = 300
)
}










Only chromosome 1
# Subset by chrom
mydf.chr1 <- mydf[which(mydf$CHROM=="1"),]
ggplot(mydf.chr1, aes(x=BIN_START, y=PI))+
geom_point()+
theme_classic()
# List of treatment data frames and their labels
df_names <- c("pi.all.df", "pi.concon.df", "pi.conrod.df", "pi.strcon.df", "pi.strrod.df")
df_labels <- c("ALL", "CONCON", "CONROD", "STRCON", "STRROD")
# Step 1: Calculate global PI range across all dataframes
all_pi_values <- unlist(lapply(df_names, function(x) get(x)$PI))
global_ymin <- min(all_pi_values, na.rm = TRUE)
global_ymax <- max(all_pi_values, na.rm = TRUE)
# Step 2: Create plots and save as PNGs
for (j in seq_along(df_names)) {
df <- get(df_names[j])
label <- df_labels[j]
for (i in 1:10) {
chr_data <- df[df$CHROM == as.character(i), ]
p <- ggplot(chr_data, aes(x = BIN_START, y = PI)) +
geom_point() +
theme_classic() +
ggtitle(paste("Treatment:", label, "- Chromosome", i)) +
labs(x = "BIN_START", y = "PI") +
ylim(global_ymin, global_ymax)
filename <- paste0("PI_", label, "_chr", i, ".png")
ggsave(filename = filename, plot = p, width = 8, height = 5, dpi = 300)
}
}
LS0tCnRpdGxlOiAiR2VuZXRpYyBEaXZlcnNpdHkgd29yayIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAzCiAgICB0b2NfZmxvYXQ6IHllcwogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6ICczJwogIGh0bWxfZG9jdW1lbnQ6CiAgICBrZWVwX21kOiBUUlVFCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgcm9vdF9kaXIgPSAiL2hvbWUvU2hhcmVkX0RhdGEvUk9EX0NBRE8vYW5hbHlzaXMvcmF3LnZjZi9maWx0ZXJlZCIpCmBgYAoKIyBMb2FkIGxpYnJhcmllcyBhbmQgZmlsZSBwYXRocwpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeSgicGx5ciIpCmxpYnJhcnkoImRwbHlyIikKbGlicmFyeSgiZ2dwbG90MiIpCmxpYnJhcnkoUi51dGlscykKbGlicmFyeShnZ2hpZ2hsaWdodCkKbGlicmFyeShnZ21hbikKbGlicmFyeShnZ3RleHQpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KHBsb3RyaXgpCmxpYnJhcnkocXFtYW4pCmxpYnJhcnkocXZhbHVlKQpsaWJyYXJ5KHJlc2hhcGUyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KHpvbykKbGlicmFyeShpbmZlcikKb3B0aW9ucyhkcGx5ci5zdW1tYXJpc2UuaW5mb3JtID0gRkFMU0UpCmxpYnJhcnkoYmlnc25wcikKbGlicmFyeSgid2VzYW5kZXJzb24iKQpsaWJyYXJ5KCJkaXJlY3RsYWJlbHMiKQpsaWJyYXJ5KE91dEZMQU5LKQpsaWJyYXJ5KGFkZWdlbmV0KQpsaWJyYXJ5KHBvcHByKQpsaWJyYXJ5KHZjZlIpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShtYXRyaXhTdGF0cykKbGlicmFyeShwdXJycikKbGlicmFyeShzY2FsZXMpIApgYGAKCiMgTnVjbGVvdGlkZSBkaXZlcnNpdHkKCk51Y2xlb3RpZGUgZGl2ZXJzaXR5IChvZnRlbiByZWZlcnJlZCB0byB1c2luZyB0aGUgc3ltYm9sIM+AKSBpcyB0aGUgYXZlcmFnZSBwYWlyd2lzZSBkaWZmZXJlbmNlIGJldHdlZW4gYWxsIHBvc3NpYmxlIHBhaXJzIG9mIGluZGl2aWR1YWxzIGluIHlvdXIgc2FtcGxlLiBJdCBpcyBhIHZlcnkgaW50dWl0aXZlIGFuZCBzaW1wbGUgbWVhc3VyZSBvZiBnZW5ldGljIGRpdmVyc2l0eSwgYW5kIGlzIGFjY3VyYXRlbHkgZXN0aW1hdGVkIGV2ZW4gd2l0aCB2ZXJ5IGZldyBzYW1wbGVzLiBBIGZvcm1hbCBkZWZpbml0aW9uIGlzIGhlcmUuCgpXZSBjYW4gb2J0YWluIHRoZSBudWNsZW90aWRlIGRpdmVyc2l0eSAoz4ApIGZyb20gb3VyIFZDRiBmaWxlIHVzaW5nIHZjZnRvb2xzIHNvZnR3YXJlLiBJbiBvdXIgY2FzZSB3ZSB3aWxsIGNvbGxlY3QgdGhlIM+AIHZhbHVlIGZyb20gZWFjaCAxMCBrYiAoMTAsMDAwIGJwKSB3aW5kb3cgb2YgdGhlIGdlbm9tZS4KCk5COiB2Y2Z0b29scyBpcyBhIHZlcnkgZmxleGlibGUgdG9vbCBmb3IgYW5hbHl6aW5nLCBtYW5pcHVsYXRpbmcgVkNGIGZpbGVzLiBJdCBjYW4gZG8gbWFueSBvdGhlciB3b25kZXJmdWwgdGhpbmdzLiBUaGUgdmNmdG9vbHMgbWFudWFsIGlzIG9uIGdpdGh1YiBoZXJlIChodHRwczovL3ZjZnRvb2xzLnNvdXJjZWZvcmdlLm5ldC9tYW5fbGF0ZXN0Lmh0bWwpLgoKIyMjIEJyZWFraW5nIHVwIHBpIGJ5IHRyZWF0bWVudCB0eXBlPwoKSSBiZWxpZXZlIHRoYXQgYW4gaW1wb3J0YW50IHN0ZXAgd291bGQgYmUgdG8gY29tcGFyZSBudWNsZW90aWRlIGRpdmVyc2l0eSBiZXR3ZWVuIHRoZSBkaWZmZXJlbnQgdHJlYXRtZW50IGdyb3Vwcy4gVGhlIGZvbGxvd2luZyBjb2RlIHByZXNlbnQgaW5mb3JtYXRpb24gZm9yIGFsbCB0cmVhdG1lbnQgZ3JvdXBzIGFuZCBjb21wYXJlcyBpdCB0byBlYWNoIGluZGl2aWR1YWwgdHJlYXRtZW50IGdyb3VwLgoKIyMgU3RhcnQgb2YgbW9kaWZpZWQgd29ya2Zsb3cKCiMjIFNldHVwIAoKVGhlIGZvbGxvd2luZyB3YXMgcnVuIG9uIHRoZSBjb21tYW5kIGxpbmUKYGBge2Jhc2h9CiMgTWFrZSBST0RfQ0FET193b3JraW5nIGRpcmVjdG9yeSBpbiBob21lCm1rZGlyIFJPRF9DQURPX3dvcmtpbmcKY2QgUk9EX0NBRE9fd29ya2luZwojIE1ha2UgTnVjbGVvdGlkZV9kaXZlcnNpdHkgZGlyZWN0b3J5Cm1rZGlyIFJPRF9DQURPX3dvcmtpbmcKIyBjcmVhdGUgcG9wbWFwIGZpbGUgd2l0aCBzYW1wbGUgYW5kIHRyZWF0bWVudCBuYW1lcwpjcCAvaG9tZS9TaGFyZWRfRGF0YS9ST0RfQ0FETy9hbmFseXNpcy9wb3BtYXAgcG9wbWFwCiMgbWFudWFsbHkgYWRkIGluIHRyZWF0bWVudCBuYW1lcyB0byBwb3BtYXAgZmlsZSAody8gY29kZSkKaGVhZCB0cmVhdF9wb3BtYXAgCmBgYApDMV8yICAgIGNvbi1jb24KQzFfNCAgICBjb24tY29uCkMxXzUgICAgY29uLWNvbgpDMV82ICAgIGNvbi1jb24KQzFfNyAgICBjb24tY29uCkMxXzggICAgY29uLWNvbgpDMV85ICAgIGNvbi1jb24KQzJfMTAgICBjb24tY29uCkMyXzExICAgY29uLWNvbgpDMl8yICAgIGNvbi1jb24KCiMgU3Vic2V0dGluZyBwb3BtYXAgZ3JvdXBzCkNyZWF0ZSB0cmVhdG1lbnQgc3BlY2lmaWMgZmlsZXMgY29udGFpbmluZyBhIHNpbmdsZSBjb2x1bW4gb2YgYWxsIG9mIHRoZSBzYW1wbGUgbmFtZXMgd2l0aGluIHRoYXQgdHJlYXRtZW50CmBgYHtiYXNofQphd2sgJyQyID09ICJjb24tY29uIiB7cHJpbnQgJDF9JyB0cmVhdF9wb3BtYXAgPiBjb24tY29uLnR4dCB8IGF3ayAnJDIgPT0gInN0ci1jb24iIHtwcmludCAkMX0nIHRyZWF0X3BvcG1hcCA+IHN0ci1jb24udHh0IHwgYXdrICckMiA9PSAiY29uLXJvZCIge3ByaW50ICQxfScgdHJlYXRfcG9wbWFwID4gY29uLXJvZC50eHQgfCBhd2sgJyQyID09ICJzdHItcm9kIiB7cHJpbnQgJDF9JyB0cmVhdF9wb3BtYXAgPiBzdHItcm9kLnR4dApgYGAKCiMjIyBSdW4gVkNGIHRvb2xzIFBJIHdpbmRvdwpgYGB7YmFzaCBldmFsID0gRkFMU0V9CiNiY2Z0b29scyB2aWV3IC0tdGhyZWFkcyAyMCAtUyBTTlAuVFJTZHAxMGcxLkZJTC52Y2YgfCB2Y2Z0b29scyAtLXZjZiAtICAtLXdpbmRvdy1waSAxMDAwMCAtLW91dCBST0QuQ0FETy5hbGwucGkKCiMgRm9yIGNvbi1jb24KIyBTdGVwIDE6IEZpbHRlciBWQ0YgZm9yIHBvcHVsYXRpb24gc3Vic2V0CnZjZnRvb2xzIC0tZ3p2Y2YgU05QLlRSU2RwMTBnMS5GSUwudmNmLmd6IC0ta2VlcCBjb24tY29uLnR4dCAtLXJlY29kZSAtLXJlY29kZS1JTkZPLWFsbCAtLW91dCB0ZW1wX2NvbmNvbl9maWx0ZXJlZAoKIyBTdGVwIDI6IGJnemlwIG91dHB1dApiZ3ppcCB0ZW1wX2NvbmNvbl9maWx0ZXJlZC5yZWNvZGUudmNmCgojIFN0ZXAgMzogQ2FsY3VsYXRlIHdpbmRvd2VkIHBpCnZjZnRvb2xzIC0tZ3p2Y2YgdGVtcF9jb25jb24uZmlsdGVyZWQucmVjb2RlLnZjZi5neiAtLXdpbmRvdy1waSAxMDAwMCAtLW91dCBST0QuQ0FETy5jb24tY29uLnBpLndpbmRvd2VkLnBpCgojIEZvciBzdHItY29uCiMgU3RlcCAxOiBGaWx0ZXIgVkNGIGZvciBwb3B1bGF0aW9uIHN1YnNldAp2Y2Z0b29scyAtLWd6dmNmIFNOUC5UUlNkcDEwZzEuRklMLnZjZi5neiAtLWtlZXAgcG9wbWFwX2ZpbGVzL3N0ci1jb24udHh0IC0tcmVjb2RlIC0tcmVjb2RlLUlORk8tYWxsIC0tb3V0IHRlbXBfc3RyY29uX2ZpbHRlcmVkCgojIFN0ZXAgMjogYmd6aXAgb3V0cHV0CmJnemlwIHRlbXBfc3RyY29uX2ZpbHRlcmVkLnJlY29kZS52Y2YKCiMgU3RlcCAzOiAjIFN0ZXAgMzogQ2FsY3VsYXRlIHdpbmRvd2VkIHBpCnZjZnRvb2xzIC0tZ3p2Y2YgdGVtcF9zdHJjb25fZmlsdGVyZWQucmVjb2RlLnZjZi5neiAtLXdpbmRvdy1waSAxMDAwMCAtLW91dCBST0QuQ0FETy5zdHItY29uLnBpLndpbmRvd2VkLnBpCgojIEZvciBjb24tcm9kCiMgU3RlcCAxOiBGaWx0ZXIgVkNGIGZvciBwb3B1bGF0aW9uIHN1YnNldAp2Y2Z0b29scyAtLWd6dmNmIFNOUC5UUlNkcDEwZzEuRklMLnZjZiAtLWtlZXAgcG9wbWFwX2ZpbGVzL2Nvbi1yb2QudHh0IC0tcmVjb2RlIC0tcmVjb2RlLUlORk8tYWxsIC0tb3V0IHRlbXBfY29ucm9kX2ZpbHRlcmVkCgojIFN0ZXAgMjogYmd6aXAgb3V0cHV0CmJnemlwIHRlbXBfY29ucm9kX2ZpbHRlcmVkLnJlY29kZS52Y2YKCiMgU3RlcCAzOiBDYWxjdWxhdGUgd2luZG93ZWQgcGkKdmNmdG9vbHMgLS1nenZjZiB0ZW1wX2NvbnJvZF9maWx0ZXJlZC5yZWNvZGUudmNmLmd6IC0td2luZG93LXBpIDEwMDAwIC0tb3V0IFJPRC5DQURPLmNvbi1yb2QucGkud2luZG93ZWQucGkKCiMgRm9yIHN0ci1yb2QKIyBTdGVwIDE6IEZpbHRlciBWQ0YgZm9yIHBvcHVsYXRpb24gc3Vic2V0CnZjZnRvb2xzIC0tZ3p2Y2YgU05QLlRSU2RwMTBnMS5GSUwudmNmIC0ta2VlcCBwb3BtYXBfZmlsZXMvc3RyLXJvZC50eHQgLS1yZWNvZGUgLS1yZWNvZGUtSU5GTy1hbGwgLS1vdXQgdGVtcF9zdHJyb2RfZmlsdGVyZWQKCiMgU3RlcCAyOiBiZ3ppcCBvdXRwdXQKYmd6aXAgdGVtcF9zdHJyb2RfZmlsdGVyZWQucmVjb2RlLnZjZgoKIyBTdGVwIDM6IENhbGN1bGF0ZSB3aW5kb3dlZCBwaQp2Y2Z0b29scyAtLWd6dmNmIHRlbXBfc3Rycm9kX2ZpbHRlcmVkLnJlY29kZS52Y2YuZ3ogLS13aW5kb3ctcGkgMTAwMDAgLS1vdXQgUk9ELkNBRE8uc3RyLXJvZC5waS53aW5kb3dlZC5waQpgYGAKCiMjIyBNYWtlIHNjcmlwdCB3aXRoIGxvb3AgdXNpbmcgQ2hhdEdQVAoKIyMjIyBNYWtlIHNjcmlwdAoKYGBge2Jhc2h9CiMhL2Jpbi9iYXNoCgpWQ0Y9U05QLlRSU2RwMTBnMS5GSUwudmNmLmd6ClBPUFM9KCJjb24tY29uIiAic3RyLWNvbiIgImNvbi1yb2QiICJzdHItcm9kIikKCmZvciBQT1AgaW4gIiR7UE9QU1tAXX0iOyBkbwogICAgZWNobyAiUHJvY2Vzc2luZyAkUE9QLi4uIgoKICAgIEtFRVA9InBvcG1hcF9maWxlcy8ke1BPUH0udHh0IgogICAgT1VUX1BSRUZJWD0idGVtcF8ke1BPUC8vLX0iCiAgICBSRUNfVkNGPSIke09VVF9QUkVGSVh9LnJlY29kZS52Y2YiCiAgICBSRUNfVkNGR1o9IiR7UkVDX1ZDRn0uZ3oiCiAgICBPVVRQVVRfUEk9IlJPRC5DQURPLiR7UE9QfS5waS53aW5kb3dlZC5waSIKCiAgICAjIFN0ZXAgMTogRmlsdGVyIGFuZCByZWNvZGUKICAgIHZjZnRvb2xzIC0tZ3p2Y2YgIiRWQ0YiIFwKICAgICAgICAtLWtlZXAgIiRLRUVQIiBcCiAgICAgICAgLS1yZWNvZGUgLS1yZWNvZGUtSU5GTy1hbGwgXAogICAgICAgIC0tb3V0ICIkT1VUX1BSRUZJWCIKCiAgICAjIFN0ZXAgMjogQ29tcHJlc3MgVkNGIGFuZCByZW1vdmUgdW5jb21wcmVzc2VkCiAgICBiZ3ppcCAiJFJFQ19WQ0YiCiAgICBybSAiJFJFQ19WQ0YiCgogICAgIyBTdGVwIDM6IENhbGN1bGF0ZSB3aW5kb3dlZCBwaQogICAgdmNmdG9vbHMgLS1nenZjZiAiJFJFQ19WQ0ZHWiIgXAogICAgICAgIC0td2luZG93LXBpIDEwMDAwIFwKICAgICAgICAtLW91dCAiJE9VVFBVVF9QSSIKCiAgICAjIFN0ZXAgNDogQ2xlYW4gdXAgY29tcHJlc3NlZCBWQ0YKICAgIHJtICIkUkVDX1ZDRkdaIgoKICAgIGVjaG8gIkZpbmlzaGVkIHByb2Nlc3NpbmcgJFBPUCIKICAgIGVjaG8gIi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSIKZG9uZQpgYGAKCiMjIyMgTWFrZSBleGVjdXRhYmxlCgpgYGB7YmFzaH0KY2htb2QgK3ggcnVuX3BpX2NhbGN1bGF0aW9ucy5zaApgYGAKCiMjIyMgUnVuIGluIHRtdXgKYGBge2Jhc2h9CiMgUnVuIGluIHRtdXgKdG11eCBuZXcgLXMgcGlfY2FsYwojIFJlYXR0YWNoIGxhdGVyCnRtdXggYXR0YWNoLXNlc3Npb24gLXQgcGlfY2FsYwpgYGAKCiMjIyBMb2FkIGRhdGFmcmFtZQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcGkuYWxsLmRhdGFmcmFtZTwtcmVhZC50YWJsZSgiL2hvbWUvU2hhcmVkX0RhdGEvUk9EX0NBRE8vYW5hbHlzaXMvcmF3LnZjZi9ST0QuQ0FETy5hbGwucGkud2luZG93ZWQucGkiLCBzZXA9Ilx0IiwgaGVhZGVyPVQpCnBpLmNvbmNvbi5kYXRhZnJhbWU8LXJlYWQudGFibGUoIi9ob21lL2pncmVlbi9ST0RfQ0FET193b3JraW5nL051Y2xlb3RpZGVfZGl2ZXJzaXR5L1JPRC5DQURPLmNvbi1jb24ucGkud2luZG93ZWQucGkud2luZG93ZWQucGkiLCBzZXA9Ilx0IiwgaGVhZGVyPVQpCnBpLmNvbnJvZC5kYXRhZnJhbWU8LXJlYWQudGFibGUoIi9ob21lL2pncmVlbi9ST0RfQ0FET193b3JraW5nL051Y2xlb3RpZGVfZGl2ZXJzaXR5L1JPRC5DQURPLmNvbi1yb2QucGkud2luZG93ZWQucGkud2luZG93ZWQucGkiLCBzZXA9Ilx0IiwgaGVhZGVyPVQpCnBpLnN0cmNvbi5kYXRhZnJhbWU8LXJlYWQudGFibGUoIi9ob21lL2pncmVlbi9ST0RfQ0FET193b3JraW5nL051Y2xlb3RpZGVfZGl2ZXJzaXR5L1JPRC5DQURPLnN0ci1jb24ucGkud2luZG93ZWQucGkud2luZG93ZWQucGkiLCBzZXA9Ilx0IiwgaGVhZGVyPVQpCnBpLnN0cnJvZC5kYXRhZnJhbWU8LXJlYWQudGFibGUoIi9ob21lL2pncmVlbi9ST0RfQ0FET193b3JraW5nL051Y2xlb3RpZGVfZGl2ZXJzaXR5L1JPRC5DQURPLnN0ci1yb2QucGkud2luZG93ZWQucGkud2luZG93ZWQucGkiLCBzZXA9Ilx0IiwgaGVhZGVyPVQpCmBgYAoKIyMjIENvbG9yIHBhbGV0dGUKYGBge3J9CiNIZXJlIGlzIHRoZSBjb2xvciBwYWxsZXR0ZSB0aGF0IHdlIHdpbGwgdXNlIGZvciBldmVyeXRoaW5nOgoKY29sX3BhbCA8LSBjKCIjMDA3MkIyIiwgIiM1NkI0RTkiLCAiI0U2OUYwMCIsICIjRjBFNDQyIikKCiNMZXQncyBmYWN0b3IgdHJlYXRtZW50cyBhcyBmb2xsb3dzOgoKZGYkVFJFQVQgPC0gZmFjdG9yKGRmJFRSRUFULCBsZXZlbHM9YygiQ09OQ09OIiwgIlNUUkNPTiIsICJDT05ST0QiLCAiU1RSUk9EIikpCmBgYAoKIyMjIE1vZGlmeSBDSFJPTSBjb2x1bW4gaW4gZGF0YWZyYW1lCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwaS5hbGwuZGF0YWZyYW1lICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4MC4xIiwgIjEiKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1NzgxLjEiLCAiMiIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODIuMSIsICIzIikpICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4My4xIiwgIjQiKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1Nzg0LjEiLCAiNSIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODUuMSIsICI2IikpICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4Ni4xIiwgIjciKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1Nzg3LjEiLCAiOCIpKSAlPiUKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4OC4xIiwgIjkiKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1Nzg5LjEiLCAiMTAiKSkgIC0+IHBpLmFsbC5kZgpwaS5hbGwuZGYkQ0hST00gPC0gYXMuZmFjdG9yKHBpLmFsbC5kZiRDSFJPTSkKCnBpLmNvbmNvbi5kYXRhZnJhbWUgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1NzgwLjEiLCAiMSIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODEuMSIsICIyIikpICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4Mi4xIiwgIjMiKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1NzgzLjEiLCAiNCIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODQuMSIsICI1IikpICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4NS4xIiwgIjYiKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1Nzg2LjEiLCAiNyIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODcuMSIsICI4IikpICU+JQogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1Nzg4LjEiLCAiOSIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODkuMSIsICIxMCIpKSAgLT4gcGkuY29uY29uLmRmCnBpLmNvbmNvbi5kZiRDSFJPTSA8LSBhcy5mYWN0b3IocGkuY29uY29uLmRmJENIUk9NKQoKcGkuY29ucm9kLmRhdGFmcmFtZSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODAuMSIsICIxIikpICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4MS4xIiwgIjIiKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1NzgyLjEiLCAiMyIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODMuMSIsICI0IikpICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4NC4xIiwgIjUiKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1Nzg1LjEiLCAiNiIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODYuMSIsICI3IikpICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4Ny4xIiwgIjgiKSkgJT4lCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODguMSIsICI5IikpICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4OS4xIiwgIjEwIikpICAtPiBwaS5jb25yb2QuZGYKcGkuY29ucm9kLmRmJENIUk9NIDwtIGFzLmZhY3RvcihwaS5jb25yb2QuZGYkQ0hST00pCgpwaS5zdHJjb24uZGF0YWZyYW1lICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4MC4xIiwgIjEiKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1NzgxLjEiLCAiMiIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODIuMSIsICIzIikpICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4My4xIiwgIjQiKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1Nzg0LjEiLCAiNSIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODUuMSIsICI2IikpICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4Ni4xIiwgIjciKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1Nzg3LjEiLCAiOCIpKSAlPiUKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4OC4xIiwgIjkiKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1Nzg5LjEiLCAiMTAiKSkgIC0+IHBpLnN0cmNvbi5kZgpwaS5zdHJjb24uZGYkQ0hST00gPC0gYXMuZmFjdG9yKHBpLnN0cmNvbi5kZiRDSFJPTSkKCnBpLnN0cnJvZC5kYXRhZnJhbWUgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1NzgwLjEiLCAiMSIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODEuMSIsICIyIikpICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4Mi4xIiwgIjMiKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1NzgzLjEiLCAiNCIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODQuMSIsICI1IikpICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4NS4xIiwgIjYiKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1Nzg2LjEiLCAiNyIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODcuMSIsICI4IikpICU+JQogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1Nzg4LjEiLCAiOSIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODkuMSIsICIxMCIpKSAgLT4gcGkuc3Rycm9kLmRmCnBpLnN0cnJvZC5kZiRDSFJPTSA8LSBhcy5mYWN0b3IocGkuc3Rycm9kLmRmJENIUk9NKQpgYGAKCiMjIyBGb3IgbG9vcCB0byByZXBsYWNlIHByZXZpb3VzIGRhdGFmcmFtZSBtYW5pcHVsYXRpb24KCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKIyBDcmVhdGUgbmFtZWQgdmVjdG9yIHRvIG1hcCBjaHJvbW9zb21lIG5hbWVzCmNocm9tX21hcCA8LSBzZXROYW1lcyhhcy5jaGFyYWN0ZXIoMToxMCksIHBhc3RlMCgiTkNfMDM1NzgiLCAwOjksICIuMSIpKQoKIyBMaXN0IG9mIG9yaWdpbmFsIGRhdGFmcmFtZSBuYW1lcyAoYXMgc3RyaW5ncykKaW5wdXRfbmFtZXMgPC0gYygKICAicGkuYWxsLmRhdGFmcmFtZSIsCiAgInBpLmNvbmNvbi5kYXRhZnJhbWUiLAogICJwaS5jb25yb2QuZGF0YWZyYW1lIiwKICAicGkuc3RyY29uLmRhdGFmcmFtZSIsCiAgInBpLnN0cnJvZC5kYXRhZnJhbWUiCikKCiMgQ29ycmVzcG9uZGluZyBvdXRwdXQgZGF0YWZyYW1lIG5hbWVzCm91dHB1dF9uYW1lcyA8LSBjKAogICJwaS5hbGwuZGYiLAogICJwaS5jb25jb24uZGYiLAogICJwaS5jb25yb2QuZGYiLAogICJwaS5zdHJjb24uZGYiLAogICJwaS5zdHJyb2QuZGYiCikKCiMgTG9vcCB0aHJvdWdoIGVhY2ggZGF0YWZyYW1lCmZvciAoaSBpbiBzZXFfYWxvbmcoaW5wdXRfbmFtZXMpKSB7CiAgZGYgPC0gZ2V0KGlucHV0X25hbWVzW2ldKSAgIyByZXRyaWV2ZSB0aGUgZGF0YWZyYW1lIGJ5IG5hbWUKICAKICAjIFJlcGxhY2UgY2hyb21vc29tZSBuYW1lcwogIGZvciAob2xkIGluIG5hbWVzKGNocm9tX21hcCkpIHsKICAgIGRmIDwtIGRmICU+JSBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgb2xkLCBjaHJvbV9tYXBbW29sZF1dKSkKICB9CiAgCiAgIyBDb252ZXJ0IHRvIGZhY3RvcgogIGRmJENIUk9NIDwtIGFzLmZhY3RvcihkZiRDSFJPTSkKICAKICAjIEFzc2lnbiB0byBuZXcgbmFtZSBpbiBnbG9iYWwgZW52aXJvbm1lbnQKICBhc3NpZ24ob3V0cHV0X25hbWVzW2ldLCBkZikKfQpgYGAKCgojIyMgRGVzY3JpcHRpdmUgc3RhdGlzdGljcwpgYGB7cn0Kc3VtbWFyeShwaS5hbGwuZGYpCmJ5KHBpLmFsbC5kZiwgcGkuYWxsLmRmJENIUk9NLCBzdW1tYXJ5KQpjb3IocGkuYWxsLmRmJE5fVkFSSUFOVFMsIHBpLmFsbC5kZiRQSSkKCnN1bW1hcnkocGkuY29uY29uLmRmKQpieShwaS5jb25jb24uZGYsIHBpLmNvbmNvbi5kZiRDSFJPTSwgc3VtbWFyeSkKY29yKHBpLmNvbmNvbi5kZiROX1ZBUklBTlRTLCBwaS5jb25jb24uZGYkUEkpCgpzdW1tYXJ5KHBpLmNvbnJvZC5kZikKYnkocGkuY29ucm9kLmRmLCBwaS5jb25yb2QuZGYkQ0hST00sIHN1bW1hcnkpCmNvcihwaS5jb25yb2QuZGYkTl9WQVJJQU5UUywgcGkuY29ucm9kLmRmJFBJKQoKc3VtbWFyeShwaS5zdHJjb24uZGYpCmJ5KHBpLnN0cmNvbi5kZiwgcGkuc3RyY29uLmRmJENIUk9NLCBzdW1tYXJ5KQpjb3IocGkuc3RyY29uLmRmJE5fVkFSSUFOVFMsIHBpLnN0cmNvbi5kZiRQSSkKCnN1bW1hcnkocGkuc3Rycm9kLmRmKQpieShwaS5zdHJyb2QuZGYsIHBpLnN0cnJvZC5kZiRDSFJPTSwgc3VtbWFyeSkKY29yKHBpLnN0cnJvZC5kZiROX1ZBUklBTlRTLCBwaS5zdHJyb2QuZGYkUEkpCmBgYAoKIyMjIE5ldyBsb29wIGFuZCBwbG90dGluZyBmb3Igc3RhdGlzdGljcwoKYGBge3J9CmNvbF9wYWwgPC0gYygKICAiQUxMIiA9ICJncmF5NzAiLAogICJDT05DT04iID0gIiMwMDcyQjIiLCAKICAiU1RSQ09OIiA9ICIjNTZCNEU5IiwgCiAgIkNPTlJPRCIgPSAiI0U2OUYwMCIsIAogICJTVFJST0QiID0gIiNGMEU0NDIiCikKCmRmX25hbWVzIDwtIGMoInBpLmFsbC5kZiIsICJwaS5jb25jb24uZGYiLCAicGkuc3RyY29uLmRmIiwgInBpLmNvbnJvZC5kZiIsICJwaS5zdHJyb2QuZGYiKQpkZl9sYWJlbHMgPC0gYygiQUxMIiwgIkNPTkNPTiIsICJTVFJDT04iLCAiQ09OUk9EIiwgIlNUUlJPRCIpCmNocm9tX2xldmVscyA8LSBhcy5jaGFyYWN0ZXIoMToxMCkKCnN1bW1hcnlfbGlzdCA8LSBsaXN0KCkKCmZvciAoaSBpbiBzZXFfYWxvbmcoZGZfbmFtZXMpKSB7CiAgZGYgPC0gZ2V0KGRmX25hbWVzW2ldKQogIHRyZWF0IDwtIGRmX2xhYmVsc1tpXQogIAogIGRmJFRSRUFUIDwtIGZhY3Rvcih0cmVhdCwgbGV2ZWxzID0gbmFtZXMoY29sX3BhbCkpCiAgCiAgY2hyb21fc3VtbWFyeSA8LSBkZiAlPiUKICAgIGdyb3VwX2J5KENIUk9NLCBUUkVBVCkgJT4lCiAgICBzdW1tYXJpc2UoCiAgICAgIG1lYW5fUEkgPSBtZWFuKFBJLCBuYS5ybSA9IFRSVUUpLAogICAgICBzZV9QSSA9IHNkKFBJLCBuYS5ybSA9IFRSVUUpIC8gc3FydChuKCkpLAogICAgICBtZWFuX05fVkFSSUFOVFMgPSBtZWFuKE5fVkFSSUFOVFMsIG5hLnJtID0gVFJVRSksCiAgICAgIHNlX05fVkFSSUFOVFMgPSBzZChOX1ZBUklBTlRTLCBuYS5ybSA9IFRSVUUpIC8gc3FydChuKCkpLAogICAgICAuZ3JvdXBzID0gImRyb3AiCiAgICApICU+JQogICAgbXV0YXRlKENIUk9NID0gZmFjdG9yKENIUk9NLCBsZXZlbHMgPSBjaHJvbV9sZXZlbHMpKQogIAogIHN1bW1hcnlfbGlzdFtbaV1dIDwtIGNocm9tX3N1bW1hcnkKfQoKc3VtbWFyeV9kZiA8LSBiaW5kX3Jvd3Moc3VtbWFyeV9saXN0KQoKbWVhbl9waV9wbG90IDwtIGdncGxvdChzdW1tYXJ5X2RmLCBhZXMoeCA9IENIUk9NLCB5ID0gbWVhbl9QSSwgZmlsbCA9IFRSRUFUKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSkgKwogIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBtZWFuX1BJIC0gc2VfUEksIHltYXggPSBtZWFuX1BJICsgc2VfUEkpLAogICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCksIHdpZHRoID0gMC4yKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sX3BhbCwgbmFtZSA9ICJUcmVhdG1lbnQiKSArCiAgbGFicyh0aXRsZSA9ICJNZWFuIFBJIHBlciBDaHJvbW9zb21lIiwgeCA9ICJDaHJvbW9zb21lIiwgeSA9ICJNZWFuIFBJIikgKwogIHRoZW1lX21pbmltYWwoKQoKbWVhbl9uX3Bsb3QgPC0gZ2dwbG90KHN1bW1hcnlfZGYsIGFlcyh4ID0gQ0hST00sIHkgPSBtZWFuX05fVkFSSUFOVFMsIGZpbGwgPSBUUkVBVCkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCkpICsKICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gbWVhbl9OX1ZBUklBTlRTIC0gc2VfTl9WQVJJQU5UUywgeW1heCA9IG1lYW5fTl9WQVJJQU5UUyArIHNlX05fVkFSSUFOVFMpLAogICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCksIHdpZHRoID0gMC4yKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sX3BhbCwgbmFtZSA9ICJUcmVhdG1lbnQiKSArCiAgbGFicyh0aXRsZSA9ICJNZWFuIG51bWJlciBvZiB2YXJpYW50cyBwZXIgQ2hyb21vc29tZSIsIHggPSAiQ2hyb21vc29tZSIsIHkgPSAiTWVhbiAjIHZhcmlhbnRzIikgKwogIHRoZW1lX21pbmltYWwoKQoKcHJpbnQobWVhbl9waV9wbG90KQpwcmludChtZWFuX25fcGxvdCkKCmdnc2F2ZSgibWVhbl9waV9wbG90LnBuZyIsIHBsb3QgPSBtZWFuX3BpX3Bsb3QsIHdpZHRoID0gMTAsIGhlaWdodCA9IDYsIGRwaSA9IDMwMCkKZ2dzYXZlKCJtZWFuX25fdmFyaWFudHNfcGxvdC5wbmciLCBwbG90ID0gbWVhbl9uX3Bsb3QsIHdpZHRoID0gMTAsIGhlaWdodCA9IDYsIGRwaSA9IDMwMCkKCmBgYAoKIyBDb3JyZWxhdGlvbiB2aXN1YWxpemF0aW9ucwpgYGB7cn0KZm9yIChpIGluIHNlcV9hbG9uZyhkZl9uYW1lcykpIHsKICBkZiA8LSBnZXQoZGZfbmFtZXNbaV0pCiAgbGFiZWwgPC0gZGZfbGFiZWxzW2ldCiAgCiAgcCA8LSBnZ3Bsb3QoZGYsIGFlcyh4ID0gTl9WQVJJQU5UUywgeSA9IFBJKSkgKwogICAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNCkgKwogICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAiYmx1ZSIpICsKICAgIGxhYnModGl0bGUgPSBwYXN0ZSgiQ29ycmVsYXRpb246IFBJIHZzICMgdmFyaWFudHMg4oCUIiwgbGFiZWwpLAogICAgICAgICB4ID0gIk5fVkFSSUFOVFMiLAogICAgICAgICB5ID0gIlBJIikgKwogICAgdGhlbWVfbWluaW1hbCgpCiAgCiAgcHJpbnQocCkKfQpgYGAKCiMjIyBUYWJsZSBvZiBjb3JyZWxhdGlvbnMKCmBgYHtyfQpjb3JfdGFibGUgPC0gdGliYmxlKAogIGRhdGFzZXQgPSBkZl9sYWJlbHMsCiAgY29ycmVsYXRpb24gPSBtYXBfZGJsKGRmX25hbWVzLCB+IGNvcihnZXQoLngpJE5fVkFSSUFOVFMsIGdldCgueCkkUEksIHVzZSA9ICJjb21wbGV0ZS5vYnMiKSkKKQoKcHJpbnQoY29yX3RhYmxlKQpgYGAKCiMjIyBQbG90IFBJIGJ5IGNocm9tb3NvbWUKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmdncGxvdChwaS5hbGwuZGYsIGFlcyh4PUNIUk9NLCB5PVBJLCkpKwogIGdlb21fdmlvbGluKGFlcyhjb2xvcj1DSFJPTSxmaWxsPUNIUk9NKSkrCiAgZ2VvbV9ib3hwbG90KGFlcyhmaWxsPUNIUk9NKSwgd2lkdGg9MC4xLG91dGxpZXIuc2hhcGUgPSAyMywgb3V0bGllci5jb2xvciA9ICJibGFjayIpKwogIHN0YXRfc3VtbWFyeShmdW49bWVhbiwgZ2VvbT0icG9pbnQiLCBzaGFwZT0yMywgc2l6ZT0yKSsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlBhaXJlZCIpKwogIHRoZW1lX2NsYXNzaWMoKQpgYGAKCiMjIyBQbG90IFBJIGJ5IGNocm9tb3NvbWUgbG9vcAoKYGBge3J9CiMgTGlzdCBvZiBkYXRhZnJhbWVzIGFuZCBsYWJlbHMKZGZfbmFtZXMgPC0gYygicGkuYWxsLmRmIiwgInBpLmNvbmNvbi5kZiIsICJwaS5jb25yb2QuZGYiLCAicGkuc3RyY29uLmRmIiwgInBpLnN0cnJvZC5kZiIpCmRmX2xhYmVscyA8LSBjKCJBbGwiLCAiQ29uQ29uIiwgIkNvblJvZCIsICJTdHJDb24iLCAiU3RyUm9kIikKCiMgU3RhbmRhcmQgY2hyb21vc29tZSBvcmRlcgpjaHJvbV9sZXZlbHMgPC0gYXMuY2hhcmFjdGVyKDE6MTApCgojIENvbWJpbmUgYWxsIGludG8gb25lIGRhdGFmcmFtZQpjb21iaW5lZF9kZiA8LSBwdXJycjo6bWFwMl9kZnIoZGZfbmFtZXMsIGRmX2xhYmVscywgZnVuY3Rpb24oZGZfbmFtZSwgbGFiZWwpIHsKICBkZiA8LSBnZXQoZGZfbmFtZSkKICBkZiAlPiUKICAgIG11dGF0ZSgKICAgICAgZGF0YXNldCA9IGxhYmVsLAogICAgICBDSFJPTSA9IGZhY3RvcihDSFJPTSwgbGV2ZWxzID0gY2hyb21fbGV2ZWxzKQogICAgKQp9KQoKIyBGYWNldGVkIHZpb2xpbiArIGJveHBsb3QKZ2dwbG90KGNvbWJpbmVkX2RmLCBhZXMoeCA9IENIUk9NLCB5ID0gUEkpKSArCiAgZ2VvbV92aW9saW4oYWVzKGNvbG9yID0gQ0hST00sIGZpbGwgPSBDSFJPTSksIHRyaW0gPSBGQUxTRSkgKwogIGdlb21fYm94cGxvdChhZXMoZmlsbCA9IENIUk9NKSwgd2lkdGggPSAwLjEsIG91dGxpZXIuc2hhcGUgPSAyMywgb3V0bGllci5jb2xvciA9ICJibGFjayIpICsKICBzdGF0X3N1bW1hcnkoZnVuID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjMsIHNpemUgPSAyKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJQYWlyZWQiKSArCiAgbGFicyh0aXRsZSA9ICJQSSBEaXN0cmlidXRpb24gYnkgQ2hyb21vc29tZSAoRmFjZXRlZCBieSBEYXRhc2V0KSIsCiAgICAgICB4ID0gIkNocm9tb3NvbWUiLCB5ID0gIlBJIikgKwogIGZhY2V0X3dyYXAofiBkYXRhc2V0LCBuY29sID0gMikgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKYGBgCgojIyMgU21hbGxlciB2aXN1YWxpemF0aW9ucwpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KaGlzdChteWRmJFBJLGJyPTQwKQoKYm94cGxvdChteWRmJFBJLCB5bGFiPSJOdWMgRGl2ZXJzaXR5IikKYGBgCgojIyMgUGxvdCBCeSBwb3NpdGlvbgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ2dwbG90KHBpLmFsbC5kZiwgYWVzKHg9QklOX1NUQVJULCB5PVBJLCBjb2xvcj1DSFJPTSkpKwogIGdlb21fcG9pbnQoKSsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlBhaXJlZCIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gbGFiZWxfbnVtYmVyKHNjYWxlID0gMWUtNiwgc3VmZml4ID0gIk0iKSkgKwogIGZhY2V0X3dyYXAofkNIUk9NKSsKICB0aGVtZV9jbGFzc2ljKCkKYGBgCiMjIyBMb29wIGZvciBwbG90IGJ5IHBvc2l0aW9uCmBgYHtyfQojIERlZmluZSBkYXRhZnJhbWUgbmFtZXMgYW5kIGxhYmVscwpkZl9uYW1lcyA8LSBjKCJwaS5hbGwuZGYiLCAicGkuY29uY29uLmRmIiwgInBpLmNvbnJvZC5kZiIsICJwaS5zdHJjb24uZGYiLCAicGkuc3Rycm9kLmRmIikKZGZfbGFiZWxzIDwtIGMoIkFMTCIsICJDT05DT04iLCAiQ09OUk9EIiwgIlNUUkNPTiIsICJTVFJST0QiKQoKIyBHZXQgZ2xvYmFsIFBJIHJhbmdlCmFsbF9waV92YWx1ZXMgPC0gdW5saXN0KGxhcHBseShkZl9uYW1lcywgZnVuY3Rpb24oeCkgZ2V0KHgpJFBJKSkKZ2xvYmFsX3ltaW4gPC0gbWluKGFsbF9waV92YWx1ZXMsIG5hLnJtID0gVFJVRSkKZ2xvYmFsX3ltYXggPC0gbWF4KGFsbF9waV92YWx1ZXMsIG5hLnJtID0gVFJVRSkKCiMgTG9vcCBvdmVyIGRhdGFmcmFtZXMKZm9yIChpIGluIHNlcV9hbG9uZyhkZl9uYW1lcykpIHsKICBkZiA8LSBnZXQoZGZfbmFtZXNbaV0pCiAgbGFiZWwgPC0gZGZfbGFiZWxzW2ldCiAgCiAgIyBFbnN1cmUgQ0hST00gaXMgYSBmYWN0b3Igb3JkZXJlZCBmcm9tIDEgdG8gMTAKICBkZiRDSFJPTSA8LSBmYWN0b3IoZGYkQ0hST00sIGxldmVscyA9IGFzLmNoYXJhY3RlcigxOjEwKSkKICAKICBwIDwtIGdncGxvdChkZiwgYWVzKHggPSBCSU5fU1RBUlQsIHkgPSBQSSwgY29sb3IgPSBDSFJPTSkpICsKICAgIGdlb21fcG9pbnQoKSArCiAgICBmYWNldF93cmFwKH5DSFJPTSkgKwogICAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJQYWlyZWQiKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gbGFiZWxfbnVtYmVyKHNjYWxlID0gMWUtNiwgc3VmZml4ID0gIk0iKSkgKyAgIyBIdW1hbiByZWFkYWJsZSB4LWF4aXMKICAgIHlsaW0oZ2xvYmFsX3ltaW4sIGdsb2JhbF95bWF4KSArICAjIFNhbWUgeS1heGlzIGZvciBhbGwgcGxvdHMKICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICBsYWJzKHRpdGxlID0gcGFzdGUoIlBJIHZzIEJJTl9TVEFSVCAtIiwgbGFiZWwpLAogICAgICAgICB4ID0gIkJJTl9TVEFSVCAobWlsbGlvbnMpIiwKICAgICAgICAgeSA9ICJQSSIpCiAgCiAgcHJpbnQocCkKICAKICBnZ3NhdmUoZmlsZW5hbWUgPSBwYXN0ZTAoIlBJX3ZzX0JJTl9TVEFSVF8iLCBsYWJlbCwgIi5wbmciKSwKICAgICAgICAgcGxvdCA9IHAsIHdpZHRoID0gMTAsIGhlaWdodCA9IDYsIGRwaSA9IDMwMCkKfQoKYGBgCgojIyMgRmFjZXQgd3JhcCBjaHJvbW9zb21lIHNob3dpbmcgdGhlbSBhY3Jvc3MgZGlmZmVyZW50IHRyZWF0bWVudCB0eXBlcwpgYGB7cn0KIyBEZWZpbmUgZGF0YWZyYW1lIG5hbWVzIGFuZCBsYWJlbHMKZGZfbmFtZXMgPC0gYygicGkuYWxsLmRmIiwgInBpLmNvbmNvbi5kZiIsICJwaS5jb25yb2QuZGYiLCAicGkuc3RyY29uLmRmIiwgInBpLnN0cnJvZC5kZiIpCmRmX2xhYmVscyA8LSBjKCJBTEwiLCAiQ09OQ09OIiwgIkNPTlJPRCIsICJTVFJDT04iLCAiU1RSUk9EIikKCiMgQ3VzdG9tIGNvbG9yIHBhbGV0dGUKY29sX3BhbCA8LSBjKAogICJBTEwiID0gImdyYXk3MCIsCiAgIkNPTkNPTiIgPSAiIzAwNzJCMiIsIAogICJTVFJDT04iID0gIiM1NkI0RTkiLCAKICAiQ09OUk9EIiA9ICIjRTY5RjAwIiwgCiAgIlNUUlJPRCIgPSAiI0YwRTQ0MiIKKQoKIyBDb21iaW5lIGFsbCBkYXRhIGludG8gb25lIGRhdGFmcmFtZSB3aXRoIHRyZWF0bWVudCBsYWJlbHMKYWxsX2RhdGEgPC0gYmluZF9yb3dzKGxhcHBseShzZXFfYWxvbmcoZGZfbmFtZXMpLCBmdW5jdGlvbihpKSB7CiAgZGYgPC0gZ2V0KGRmX25hbWVzW2ldKQogIGRmJFRyZWF0bWVudCA8LSBkZl9sYWJlbHNbaV0KICBkZgp9KSkKCiMgU2V0IENIUk9NIGFuZCBUcmVhdG1lbnQgYXMgb3JkZXJlZCBmYWN0b3JzCmFsbF9kYXRhJENIUk9NIDwtIGZhY3RvcihhbGxfZGF0YSRDSFJPTSwgbGV2ZWxzID0gYXMuY2hhcmFjdGVyKDE6MTApKQphbGxfZGF0YSRUcmVhdG1lbnQgPC0gZmFjdG9yKGFsbF9kYXRhJFRyZWF0bWVudCwgbGV2ZWxzID0gZGZfbGFiZWxzKQoKIyBHZXQgZ2xvYmFsIFBJIHJhbmdlCmdsb2JhbF95bWluIDwtIG1pbihhbGxfZGF0YSRQSSwgbmEucm0gPSBUUlVFKQpnbG9iYWxfeW1heCA8LSBtYXgoYWxsX2RhdGEkUEksIG5hLnJtID0gVFJVRSkKCiMgTG9vcCB0aHJvdWdoIGNocm9tb3NvbWVzIDEgdG8gMTAKZm9yIChjaHIgaW4gMToxMCkgewogIGNocl9zdHIgPC0gYXMuY2hhcmFjdGVyKGNocikKICBjaHJfZGF0YSA8LSBmaWx0ZXIoYWxsX2RhdGEsIENIUk9NID09IGNocl9zdHIpCiAgCiAgcCA8LSBnZ3Bsb3QoY2hyX2RhdGEsIGFlcyh4ID0gQklOX1NUQVJULCB5ID0gUEksIGNvbG9yID0gVHJlYXRtZW50KSkgKwogICAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNiwgc2l6ZSA9IDAuNSkgKwogICAgZmFjZXRfd3JhcCh+VHJlYXRtZW50LCBucm93ID0gMSkgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbF9wYWwpICsKICAgIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9udW1iZXIoc2NhbGUgPSAxZS02LCBzdWZmaXggPSAiTSIpKSArCiAgICB5bGltKGdsb2JhbF95bWluLCBnbG9iYWxfeW1heCkgKwogICAgdGhlbWVfY2xhc3NpYygpICsKICAgIGxhYnMoCiAgICAgIHRpdGxlID0gcGFzdGUoIkNocm9tb3NvbWUiLCBjaHIsICItIFBJIGFjcm9zcyBUcmVhdG1lbnQgVHlwZXMiKSwKICAgICAgeCA9ICJCSU5fU1RBUlQgKG1pbGxpb25zKSIsCiAgICAgIHkgPSAiUEkiCiAgICApCiAgCiAgcHJpbnQocCkKICAKICBnZ3NhdmUoCiAgICBmaWxlbmFtZSA9IHBhc3RlMCgiUElfY2hyIiwgY2hyLCAiX2Fjcm9zc190cmVhdG1lbnRzLnBuZyIpLAogICAgcGxvdCA9IHAsCiAgICB3aWR0aCA9IDE2LAogICAgaGVpZ2h0ID0gNCwKICAgIGRwaSA9IDMwMAogICkKfQoKYGBgCiMjIyBPbmx5IGNocm9tb3NvbWUgMQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBTdWJzZXQgYnkgY2hyb20KbXlkZi5jaHIxIDwtIG15ZGZbd2hpY2gobXlkZiRDSFJPTT09IjEiKSxdCgpnZ3Bsb3QobXlkZi5jaHIxLCBhZXMoeD1CSU5fU1RBUlQsIHk9UEkpKSsKICBnZW9tX3BvaW50KCkrCiAgdGhlbWVfY2xhc3NpYygpCmBgYAoKYGBge3J9CiMgTGlzdCBvZiB0cmVhdG1lbnQgZGF0YSBmcmFtZXMgYW5kIHRoZWlyIGxhYmVscwpkZl9uYW1lcyA8LSBjKCJwaS5hbGwuZGYiLCAicGkuY29uY29uLmRmIiwgInBpLmNvbnJvZC5kZiIsICJwaS5zdHJjb24uZGYiLCAicGkuc3Rycm9kLmRmIikKZGZfbGFiZWxzIDwtIGMoIkFMTCIsICJDT05DT04iLCAiQ09OUk9EIiwgIlNUUkNPTiIsICJTVFJST0QiKQoKIyBTdGVwIDE6IENhbGN1bGF0ZSBnbG9iYWwgUEkgcmFuZ2UgYWNyb3NzIGFsbCBkYXRhZnJhbWVzCmFsbF9waV92YWx1ZXMgPC0gdW5saXN0KGxhcHBseShkZl9uYW1lcywgZnVuY3Rpb24oeCkgZ2V0KHgpJFBJKSkKZ2xvYmFsX3ltaW4gPC0gbWluKGFsbF9waV92YWx1ZXMsIG5hLnJtID0gVFJVRSkKZ2xvYmFsX3ltYXggPC0gbWF4KGFsbF9waV92YWx1ZXMsIG5hLnJtID0gVFJVRSkKCiMgU3RlcCAyOiBDcmVhdGUgcGxvdHMgYW5kIHNhdmUgYXMgUE5Hcwpmb3IgKGogaW4gc2VxX2Fsb25nKGRmX25hbWVzKSkgewogIGRmIDwtIGdldChkZl9uYW1lc1tqXSkKICBsYWJlbCA8LSBkZl9sYWJlbHNbal0KICAKICBmb3IgKGkgaW4gMToxMCkgewogICAgY2hyX2RhdGEgPC0gZGZbZGYkQ0hST00gPT0gYXMuY2hhcmFjdGVyKGkpLCBdCiAgICAKICAgIHAgPC0gZ2dwbG90KGNocl9kYXRhLCBhZXMoeCA9IEJJTl9TVEFSVCwgeSA9IFBJKSkgKwogICAgICBnZW9tX3BvaW50KCkgKwogICAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgICBnZ3RpdGxlKHBhc3RlKCJUcmVhdG1lbnQ6IiwgbGFiZWwsICItIENocm9tb3NvbWUiLCBpKSkgKwogICAgICBsYWJzKHggPSAiQklOX1NUQVJUIiwgeSA9ICJQSSIpICsKICAgICAgeWxpbShnbG9iYWxfeW1pbiwgZ2xvYmFsX3ltYXgpCiAgICAKICAgIGZpbGVuYW1lIDwtIHBhc3RlMCgiUElfIiwgbGFiZWwsICJfY2hyIiwgaSwgIi5wbmciKQogICAgZ2dzYXZlKGZpbGVuYW1lID0gZmlsZW5hbWUsIHBsb3QgPSBwLCB3aWR0aCA9IDgsIGhlaWdodCA9IDUsIGRwaSA9IDMwMCkKICB9Cn0KCmBgYAoKCiMgUnVucyBvZiBob21venlnb3NpdHkKClJ1bnMgb2YgaG9tb3p5Z29zaXR5IChST0gpIGFyZSBjb250aWd1b3VzIGxlbmd0aHMgb2YgaG9tb3p5Z291cyBnZW5vdHlwZXMgdGhhdCBhcmUgcHJlc2VudCBpbiBhbiBpbmRpdmlkdWFsIGR1ZSB0byBwYXJlbnRzIHRyYW5zbWl0dGluZyBpZGVudGljYWwgaGFwbG90eXBlcyB0byB0aGVpciBvZmZzcHJpbmcuCgpUaGUgcG90ZW50aWFsIG9mIHByZWRpY3Rpbmcgb3IgZXN0aW1hdGluZyBpbmRpdmlkdWFsIGF1dG96eWdvc2l0eSBmb3IgYSBzdWJwb3B1bGF0aW9uIGlzIHRoZSBwcm9wb3J0aW9uIG9mIHRoZSBhdXRvc29tYWwgZ2Vub21lIGFib3ZlIGEgc3BlY2lmaWVkIGxlbmd0aCwgdGVybWVkIEZyb2guCgpUaGlzIHRlY2huaXF1ZSBjYW4gYmUgdXNlZCB0byBpZGVudGlmeSB0aGUgZ2Vub21pYyBmb290cHJpbnQgb2YgaW5icmVlZGluZyBpbiBjb25zZXJ2YXRpb24gcHJvZ3JhbXMsIGFzIG9yZ2FuaXNtcyB0aGF0IGhhdmUgdW5kZXJnb25lIHJlY2VudCBpbmJyZWVkaW5nIHdpbGwgZXhoaWJpdCBsb25nIHJ1bnMgb2YgaG9tb3p5Z29zaXR5LiBUaGUgZWZmZWN0IG9mIGluYnJlZWRpbmcgaW4gdGhlIHJlc3VsdGluZyBzdWItcG9wdWxhdGlvbnMgY291bGQgYmUgc3R1ZGllZCBieSBtZWFzdXJpbmcgdGhlIHJ1bnMgb2YgaG9tb3p5Z29zaXR5IGluIGRpZmZlcmVudCBpbmRpdmlkdWFscy4KCiMjIFN0YXJ0IFJPSCB3b3JrZmxvdwoKYGBge2Jhc2h9CnZjZnRvb2xzIC0tdmNmIFNOUC5UUlNkcDEwZzEuRklMLnZjZiAtLUxST0ggLS1vdXQgUk9ELkNBRE8uYWxsLkxST0gKYGBgCgo=